﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XFGameFramework.OctreeSystem;

public class OctreeSphereBounds : OctreeBounds
{

    #region 字段

    [Tooltip("半径")]
    [SerializeField]
    private float radius = 1;


    [Tooltip("中心")]
    [SerializeField]
    private Vector3 center;

    private Vector3 p;

    [Tooltip("世界坐标中的边界!")]
    private Bounds world_bounds;

    #endregion


    #region 属性

    public float Radius
    {
        get { 
            return radius;
        }
        set {
            radius = value;
        }
    }

    public Vector3 Center
    {
        get { 
            return center;
        }
        set { 
            center = value;
        }
    }


    private float RealRadius {
        get {

            if (radius < 0)
                return 0;

            float scale = Mathf.Abs( transform.lossyScale.x);

            if (scale > Mathf.Abs(transform.lossyScale.y))
                scale = Mathf.Abs(transform.lossyScale.y);


            if (scale > Mathf.Abs(transform.lossyScale.z))
                scale = Mathf.Abs(transform.lossyScale.z);

            return scale * radius;
        }
    }

    #endregion

#if UNITY_EDITOR

    private void OnDrawGizmos()
    { 
        Gizmos.color = Color.green; 
        Gizmos.DrawWireSphere(transform.localToWorldMatrix.MultiplyPoint(Center), RealRadius);
    }

#endif

    #region 抽象方法

    public override Vector3 ClosestPoint(Vector3 point)
    {
        if(Contains(point)) return point;

        Vector3 c = transform.localToWorldMatrix.MultiplyPoint(Center);
        return c + (point - c).normalized * RealRadius;
    }

    public override bool Contains(Vector3 point)
    {
        Vector3 c = transform.localToWorldMatrix.MultiplyPoint(Center);
        return Vector3.Distance(c,point) <= RealRadius;
    }

    public override bool IntersectRay(Ray ray, float distance = -1)
    {
        IntersectInfo info;
        return IntersectRay(ray, out info, distance);
    }

    public override bool IntersectRay(Ray ray, out IntersectInfo info, float distance = -1)
    {
        info = new IntersectInfo();
        info.bounds = this;

        if (Contains(ray.origin)) 
        {
            info.point = ray.origin;
            return true;
        }

        Vector3 center = transform.localToWorldMatrix.MultiplyPoint(Center);

        Vector3 direction = center - ray.origin;

        float angle = Vector3.Angle(direction, ray.direction);

        if (angle >= 90)
        {
            // 不会相交
            return false;
        }

        float d = Mathf.Sin(angle * Mathf.Deg2Rad) * Vector3.Distance(center,ray.origin);

        float length = d / Mathf.Tan(angle * Mathf.Deg2Rad) - Mathf.Sin(Mathf.Acos(d / RealRadius)) * RealRadius;

         
        if (d <= 0.001f) 
        {
            length = Vector3.Distance(center, ray.origin) - RealRadius;
        }

        if (Mathf.Abs(d - RealRadius) <= 0.001f) 
        {
            length =  d / Mathf.Tan(angle * Mathf.Deg2Rad);
        }

        info.point = ray.GetPoint(length);

        if (distance >= 0 && length > distance) 
            return false;

        if (d <= RealRadius) 
        {
            info.normal = (info.point - center).normalized;
            return true;
        }

        return false;
    }

    public override bool Intersects(Bounds bounds)
    {
        Vector3 c = transform.localToWorldMatrix.MultiplyPoint(Center);
        return Vector3.Distance(bounds.ClosestPoint(c), c) <= RealRadius;
    }

    public override bool Intersects(OctreeBounds octreeBounds)
    {
        Vector3 c = transform.localToWorldMatrix.MultiplyPoint(Center);
        return Vector3.Distance(octreeBounds.ClosestPoint(c), c) <= RealRadius;
    }

    public override Bounds GetBounds()
    {
        world_bounds.center = transform.localToWorldMatrix.MultiplyPoint(Center);
        world_bounds.size = new Vector3(RealRadius, RealRadius, RealRadius); 
        return world_bounds;
    }


    #endregion

}
